package Task.TaskUnitTest;

import static org.junit.Assert.*;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.junit.Before;
import org.junit.Test;

import Task.DSTask;

//@author A0094762W
/**
 * Unit tests for the DSTask class
 */
public class DSTaskTest {
	private DSTask task1, task2;
	
	@Before
	public void setUp() throws Exception {
		task1 = new DSTask();
		task2 = new DSTask();
	}
	
	// Test for 'null' partition for task name
	@Test (expected = NullPointerException.class)
	public void testCompareToForNullTaskName() throws NullPointerException {
		task2.setTaskName(null);
		task1.compareTo(task2);
	}
	
	// Test for 'empty string' partition for task name
	@Test
	public void testCompareToForEmptyStringTaskName() {
		task1.setTaskName("");
		task2.setTaskName("");
		assertTrue("comparison of empty task names", task1.compareTo(task2) == 0);
	}
	
	@Test
	public void testCompareToForTaskName() throws ParseException {
		task1 = new DSTask();
		task1.setTaskName("Task 1");
		task2 = new DSTask();
		task2.setTaskName("Task 1");
		
		// Test for 'same task' partition
		assertTrue("comparison of same task", task1.compareTo(task1) == 0);
		// Test for 'same name' partition
		assertTrue("comparison of tasks with same name",
							 task1.compareTo(task2) == 0);
		
		task1.setTaskName("A task");
		task2.setTaskName("Z task");
		// Test for 'alphabetically different' partition
		assertTrue("comparison of tasks with different name",
							 task1.compareTo(task2) < 0);
		assertTrue("comparison of tasks with different name",
							 task2.compareTo(task1) > 0);
		assertTrue("alphabetical comparison of task name",
							 task1.compareTo(task2) < 0);
		assertTrue("alphabetical comparison of task name",
							 task2.compareTo(task1) > 0);
		
		task2.setTaskName("a task");
		// Test for 'same name, different case' partition
		assertTrue("case-insensitive comparison of task name",
							 task1.compareTo(task2) == 0);
		assertTrue("case-insensitive comparison of task name",
							 task2.compareTo(task1) == 0);
		
		task1.setTaskName("Task 1");
		// Test for 'different name, different case' partition
		assertTrue("alphabetical comparison of task name with different case",
							 task1.compareTo(task2) > 0);
		assertTrue("alphabetical comparison of task name with different case",
							 task2.compareTo(task1) < 0);
		
		task1.setTaskName("1 Task Today");
		task2.setTaskName("2 Task Today");
		// Test for 'names with numerals' partition
		assertTrue("Task name with numerals",
							 task1.compareTo(task2) < 0);
		assertTrue("Task name with numerals",
							 task2.compareTo(task1) > 0);
		
		
		task1.setTaskName("One Task Today");
		// Test for 'numerals vs non-numerals' partition
		assertTrue("Comparison between task name with numerals vs alphabets",
							 task1.compareTo(task2) > 0);
		assertTrue("Comparison between task name with numerals vs alphabets",
							 task2.compareTo(task1) < 0);
	}
	
	@Test
	public void testCompareToForDefaultTime() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		assertTrue("Comparison between default start and end time",
							 task1.compareTo(task2) == 0);
		assertTrue("Comparison between default start and end time",
							 task2.compareTo(task1) == 0);
		
		task1.setTaskEndTime(2359);
		assertTrue("Comparison between no time vs end time",
							 task1.compareTo(task2) == 1);
		assertTrue("Comparison between no time vs end time",
							 task2.compareTo(task1) == -1);
		
		task1.setTaskStartTime(0000);
		assertTrue("Comparison between no time vs start & end time",
							 task1.compareTo(task2) == 1);
		assertTrue("Comparison between no time vs start & end time",
							 task2.compareTo(task1) == -1);
	}
	
	@Test
	public void testCompareToForEndTime() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		task1.setTaskEndTime(2359);
		task2.setTaskEndTime(0000);
		assertTrue("Comparison between end time", task1.compareTo(task2) == 1);
		assertTrue("Comparison between end time", task2.compareTo(task1) == -1);
		
		task1.setTaskEndTime(1200);
		task2.setTaskEndTime(1200);
		assertTrue("Comparison between end time", task1.compareTo(task2) == 0);
		assertTrue("Comparison between end time", task2.compareTo(task1) == 0);
	}
	
	@Test
	public void testCompareToForStartAndEndTime() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		task1.setTaskStartTime(0000);
		task1.setTaskEndTime(1200);
		task2.setTaskEndTime(0000);
		assertTrue("Start+end time vs end time, when start == end",
							 task1.compareTo(task2) == -1);
		assertTrue("Start+end time vs end time, when start == end",
							 task2.compareTo(task1) == 1);
		
		task1.setTaskStartTime(1000);
		assertTrue("Start+end time vs end time, when start > end",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end time vs end time, when start > end",
				 			 task2.compareTo(task1) == -1);
		
		task2.setTaskEndTime(1100);
		assertTrue("Start+end time vs end time, when start1 < end2 < end1",
				 task1.compareTo(task2) == -1);
		assertTrue("Start+end time vs end time, when start1 < end2 < end1",
	 			 task2.compareTo(task1) == 1);
		
		task2.setTaskStartTime(1000);
		assertTrue("Start+end time vs start+end time, when " +
							 "start1 == start2 but end1 > end2",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end time vs start+end time, when " +
				 			 "start1 == start2 but end1 > end2",
				 			 task2.compareTo(task1) == -1);
		
		task1.setTaskEndTime(1100);
		assertTrue("Start+end time vs start+end time, when " +
							 "start1 == start2 & end1 == end2",
							 task1.compareTo(task2) == 0);
		assertTrue("Start+end time vs start+end time, when " +
				 			 "start1 == start2 & end1 == end2",
				 			 task2.compareTo(task1) == 0);
		
		task1.setTaskStartTime(1030);
		assertTrue("Start+end time vs start+end time, when " +
							 "start1 > start2 & end1 == end2",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end time vs start+end time, when " +
				 			 "start1 > start2 & end1 == end2",
				 			 task2.compareTo(task1) == -1);
		
		task1.setTaskStartTime(900);
		task1.setTaskEndTime(2359);
		task2.setTaskStartTime(1000);
		task2.setTaskEndTime(1030);
		assertTrue("Start+end time vs start+end time, when " +
							 "start1 < start2 & end1 > end2",
							 task1.compareTo(task2) == -1);
		assertTrue("Start+end time vs start+end time, when " +
				 			 "start1 < start2 & end1 > end2",
				 			 task2.compareTo(task1) == 1);
	}
	
	@Test
	public void testCompareToForDefaultDate() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		assertTrue("Comparison between default start and end date",
							 task1.compareTo(task2) == 0);
		assertTrue("Comparison between default start and end date",
							 task2.compareTo(task1) == 0);
		
		task1.setTaskEndDate("05-24-2014");
		assertTrue("Comparison between no date vs end date",
							 task1.compareTo(task2) == 1);
		assertTrue("Comparison between no date vs end date",
							 task2.compareTo(task1) == -1);
		
		task1.setTaskStartDate("05-05-2014");
		assertTrue("Comparison between no date vs start & end date",
							 task1.compareTo(task2) == 1);
		assertTrue("Comparison between no date vs start & end date",
							 task2.compareTo(task1) == -1);
	}
	
	@Test
	public void testCompareToForEndDate() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		task1.setTaskEndDate("05-24-2014");
		task2.setTaskEndDate("05-04-2014");
		assertTrue("Comparison between end date", task1.compareTo(task2) == 1);
		assertTrue("Comparison between end date", task2.compareTo(task1) == -1);
		
		task1.setTaskEndDate("05-24-2014");
		task2.setTaskEndDate("05-24-2014");
		assertTrue("Comparison between end date", task1.compareTo(task2) == 0);
		assertTrue("Comparison between end date", task2.compareTo(task1) == 0);
	}
	
	@Test
	public void testCompareToForStartAndEndDateForTaskNotInProcess()
		throws ParseException {
		
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		task1.setTaskStartDate("05-24-2014");
		task1.setTaskEndDate("05-27-2014");
		task2.setTaskEndDate("05-24-2014");
		assertTrue("Start+end date vs end date, when start == end",
							 task1.compareTo(task2) == -1);
		assertTrue("Start+end date vs end date, when start == end",
							 task2.compareTo(task1) == 1);
		
		task1.setTaskStartDate("05-25-2014");
		assertTrue("Start+end date vs end date, when start > end",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end date vs end date, when start > end",
				 			 task2.compareTo(task1) == -1);
		
		task2.setTaskEndDate("05-26-2014");
		assertTrue("Start+end date vs end date, when start1 < end2 < end1",
				 task1.compareTo(task2) == -1);
		assertTrue("Start+end date vs end date, when start1 < end2 < end1",
	 			 task2.compareTo(task1) == 1);
		
		task2.setTaskStartDate("05-25-2014");
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 == start2 but end1 > end2",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 == start2 but end1 > end2",
				 			 task2.compareTo(task1) == -1);

		task1.setTaskEndDate("05-26-2014");
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 == start2 & end1 == end2",
							 task1.compareTo(task2) == 0);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 == start2 & end1 == end2",
				 			 task2.compareTo(task1) == 0);
		
		task1.setTaskStartDate("05-25-2014");
		task1.setTaskEndDate("05-29-2014");
		task2.setTaskStartDate("05-22-2014");
		task2.setTaskEndDate("05-29-2014");
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 > start2 & end1 == end2",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 > start2 & end1 == end2",
				 			 task2.compareTo(task1) == -1);
		
		task1.setTaskStartDate("05-01-2014");
		task1.setTaskEndDate("05-30-2014");
		task2.setTaskStartDate("05-10-2014");
		task2.setTaskEndDate("05-20-2014");
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 < start2 & end1 > end2",
							 task1.compareTo(task2) == -1);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 < start2 & end1 > end2",
				 			 task2.compareTo(task1) == 1);
	}
	
	@Test
	public void testCompareToForStartAndEndDateForOneTaskInProcess()
		throws ParseException {
		
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		Date tenDaysBeforeToday = getDateIncrementedFromToday(-10);
		Date tenDaysAfterToday = getDateIncrementedFromToday(10);
		Date fiveDaysAfterToday = getDateIncrementedFromToday(5);
		task1.setTaskStartDate(tenDaysBeforeToday);
		task1.setTaskEndDate(tenDaysAfterToday);
		task2.setTaskEndDate(fiveDaysAfterToday);
		assertTrue("Start+end date vs end date, when start1 < end2 < end1",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end date vs end date, when start1 < end2 < end1",
							 task2.compareTo(task1) == -1);
		
		task1.setTaskStartDate(fiveDaysAfterToday);
		task1.setTaskEndDate(tenDaysAfterToday);
		task2.setTaskStartDate(tenDaysBeforeToday);
		task2.setTaskEndDate(tenDaysAfterToday);
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 > start2 & end1 == end2",
							 task1.compareTo(task2) == -1);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 > start2 & end1 == end2",
				 			 task2.compareTo(task1) == 1);
		
		Date sevenDaysAfterToday = getDateIncrementedFromToday(7);
		task1.setTaskStartDate(tenDaysBeforeToday);
		task1.setTaskEndDate(tenDaysAfterToday);
		task2.setTaskStartDate(fiveDaysAfterToday);
		task2.setTaskEndDate(sevenDaysAfterToday);
		assertTrue("Start+end date vs start+end date, when " +
							 "start1 < start2 & end1 > end2",
							 task1.compareTo(task2) == 1);
		assertTrue("Start+end date vs start+end date, when " +
				 			 "start1 < start2 & end1 > end2",
				 			 task2.compareTo(task1) == -1);
	}
	
	@Test
	public void testCompareToForTaskStatus() throws ParseException {
		task1 = new DSTask();
		task2 = new DSTask();
		task1.setTaskName("same name");
		task2.setTaskName("same name");
		
		Date tenDaysBeforeToday = getDateIncrementedFromToday(-10);
		task1.setTaskEndDate(tenDaysBeforeToday);
		assertTrue("Overdue task vs not done task",
				 			 task1.compareTo(task2) == -1);
		assertTrue("Overdue task vs not done task",
	 			 			 task2.compareTo(task1) == 1);
		
		Date tenDaysAfterToday = getDateIncrementedFromToday(10);
		task2.setTaskStartDate(tenDaysBeforeToday);
		task2.setTaskEndDate(tenDaysAfterToday);
		assertTrue("Overdue task vs in process task",
							 task1.compareTo(task2) == -1);
		assertTrue("Overdue task vs in process task",
	 			 			 task2.compareTo(task1) == 1);
		
		task2.setIsDone(true);
		assertTrue("Overdue task vs done task",
							 task1.compareTo(task2) == -1);
		assertTrue("Overdue task vs done task",
							 task2.compareTo(task1) == 1);
		
		task1.setTaskStartDate(tenDaysBeforeToday);
		task1.setTaskEndDate(tenDaysAfterToday);
		task2.setIsDone(false);
		assertTrue("in process task vs not done task",
				 			 task1.compareTo(task2) == 0);
		assertTrue("in process task vs not done task",
							 task2.compareTo(task1) == 0);
		
		task2.setIsDone(true);
		assertTrue("in process task vs done task",
	 			 			 task1.compareTo(task2) == -1);
		assertTrue("in process task vs done task",
				 			 task2.compareTo(task1) == 1);
		
		task1 = new DSTask();
		task1.setTaskName("same name");
		assertTrue("not done task vs done task",
	 			 			 task1.compareTo(task2) == -1);
		assertTrue("not done task vs done task",
							 task2.compareTo(task1) == 1);
	}
	
	private Date getDateIncrementedFromToday(int amount) {
		Calendar calendar = new GregorianCalendar();
		calendar.add(Calendar.DAY_OF_MONTH, amount);
		
		return calendar.getTime();
	}
}
